{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将所有特征串联起来，构成RS_Train.csv\n",
    "#RS_Test.csv\n",
    "#为最后推荐系统做准备\n",
    "from __future__ import division\n",
    "\n",
    "import pickle\n",
    "import numpy as np\n",
    "import scipy.io as sio\n",
    "import scipy.sparse as ss\n",
    "from numpy.random import random  \n",
    "from collections import defaultdict\n",
    "from math import sqrt \n",
    "class RecommonderSystem:\n",
    "    def __init__(self):\n",
    "        # 读入数据做初始化\n",
    "\n",
    "        #用户和活动新的索引\n",
    "        self.userIndex = pickle.load(open(\"PE_userIndex.pkl\", 'rb'))\n",
    "        self.eventIndex = pickle.load(open(\"PE_eventIndex.pkl\", 'rb'))\n",
    "        self.n_users = len(self.userIndex)\n",
    "        self.n_items = len(self.eventIndex)\n",
    "\n",
    "        #用户-活动关系矩阵R\n",
    "        #在train_SVD会重新从文件中读取,二者要求的格式不同，来不及统一了:(\n",
    "        self.userEventScores = sio.mmread(\"PE_userEventScores\").todense()\n",
    "\n",
    "        #倒排表\n",
    "        ##每个用户参加的事件\n",
    "        self.itemsForUser = pickle.load(open(\"PE_eventsForUser.pkl\", 'rb'))\n",
    "        ##事件参加的用户\n",
    "        self.usersForItem = pickle.load(open(\"PE_usersForEvent.pkl\", 'rb'))\n",
    "\n",
    "        #基于模型的协同过滤参数初始化,训练\n",
    "        self.init_SVD()\n",
    "        self.train_SVD(trainfile = \"train.csv\")\n",
    "\n",
    "        #根据用户属性计算出的用户之间的相似度\n",
    "        self.userSimMatrix = sio.mmread(\"US_userSimMatrix\").todense()\n",
    "\n",
    "        #根据活动属性计算出的活动之间的相似度\n",
    "        self.eventPropSim = sio.mmread(\"EV_eventPropSim\").todense()\n",
    "        self.eventContSim = sio.mmread(\"EV_eventContSim\").todense()\n",
    "\n",
    "        #每个用户的朋友的数目\n",
    "        self.numFriends = sio.mmread(\"UF_numFriends\")\n",
    "        #用户的每个朋友参加活动的分数对该用户的影响\n",
    "        self.userFriends = sio.mmread(\"UF_userFriends\").todense()\n",
    "\n",
    "        #活动本身的热度\n",
    "        self.eventPopularity = sio.mmread(\"EA_eventPopularity\").todense()\n",
    "\n",
    "    def init_SVD(self, K=20):\n",
    "        #初始化模型参数（for 基于模型的协同过滤SVD_CF）\n",
    "        self.K = K  \n",
    "\n",
    "        #init parameters\n",
    "        #bias\n",
    "        self.bi = np.zeros(self.n_items)  \n",
    "        self.bu = np.zeros(self.n_users)  \n",
    "\n",
    "        #the small matrix\n",
    "        self.P = random((self.n_users,self.K))/10*(np.sqrt(self.K))\n",
    "        self.Q = random((self.K, self.n_items))/10*(np.sqrt(self.K))  \n",
    "                  \n",
    "          \n",
    "    def train_SVD(self,trainfile = 'train.csv', steps=100,gamma=0.04,Lambda=0.15):\n",
    "        #训练SVD模型（for 基于模型的协同过滤SVD_CF）\n",
    "        #gamma：为学习率\n",
    "        #Lambda：正则参数\n",
    "\n",
    "        #偷懒了，为了和原来的代码的输入接口一样，直接从训练文件中去读取数据\n",
    "        print(\"SVD Train...\")\n",
    "        ftrain = open(trainfile, 'r')\n",
    "        ftrain.readline()\n",
    "        self.mu = 0.0\n",
    "        n_records = 0\n",
    "        uids = []  #每条记录的用户索引\n",
    "        i_ids = [] #每条记录的item索引\n",
    "        #用户-Item关系矩阵R（内容同userEventScores相同），临时变量，训练完了R不再需要\n",
    "        R = np.zeros((self.n_users, self.n_items))\n",
    "\n",
    "        for line in ftrain:\n",
    "            cols = line.strip().split(\",\")\n",
    "            u = self.userIndex[cols[0]]  #用户\n",
    "            i = self.eventIndex[cols[1]] #活动\n",
    "\n",
    "            uids.append(u)\n",
    "            i_ids.append(i)\n",
    "\n",
    "            R[u,i] = int(cols[4])  #interested\n",
    "            self.mu += R[u,i]\n",
    "            n_records += 1\n",
    "\n",
    "        ftrain.close()\n",
    "        self.mu /= n_records\n",
    "        print(self.mu)\n",
    "        #用梯度下降的更新公式计算R Q bu bi\n",
    "        for step in range(steps):\n",
    "            print(step)\n",
    "            for u in range(len(R)):\n",
    "                for i in range(len(R[u])):\n",
    "                    if R[u][i] > 0:\n",
    "                        eui = R[u][i] - np.dot(self.P[u,:],self.Q[:,i]) - self.bu[u] - self.bi[i] -self.mu\n",
    "                        self.bu[u] =  self.bu[u] + gamma * (eui  - Lambda * self.bu[u])\n",
    "                        self.bi[i] =  self.bi[i] + gamma * (eui  - Lambda * self.bi[i])\n",
    "                        for k in range(self.K):\n",
    "                            self.P[u][k] = self.P[u][k] + gamma * (eui * self.Q[k][i] - Lambda * self.P[u][k])\n",
    "                            self.Q[k][i] = self.Q[k][i] + gamma * (eui * self.P[u][k] - Lambda * self.Q[k][i])    \n",
    "\n",
    "        # 请补充完整SVD模型训练过程\n",
    "        print(\"SVD trained\")\n",
    "    \n",
    "    def pred_SVD(self, uid, i_id):\n",
    "        #根据当前参数，预测用户uid对Item（i_id）的打分        \n",
    "        ans=self.mu + self.bi[i_id] + self.bu[uid] + np.dot(self.P[uid,:],self.Q[:,i_id])  \n",
    "\n",
    "        #将打分范围控制在0-1之间\n",
    "        if ans>1:  \n",
    "           return 1  \n",
    "        elif ans<0:  \n",
    "           return 0\n",
    "        return ans  \n",
    "\n",
    "    def sim_cal_UserCF(self, uid1, uid2 ):\n",
    "        #请补充基于用户的协同过滤中的两个用户uid1和uid2之间的相似度（根据两个用户对item打分的相似度）\n",
    "        similarity = 0.0\n",
    "        #1.找到两个用户都打过分的item\n",
    "        user1event = self.itemsForUser[uid1]\n",
    "        user2event = self.itemsForUser[uid2]\n",
    "        #2.用公式计算相似度\n",
    "        sum_x = 0  \n",
    "        sum_y = 0\n",
    "        n = 0  \n",
    "        sum_ExEy = 0\n",
    "        sum_Dx = 0\n",
    "        sum_Dy =0\n",
    "        #3.计算两个用户都打过分的item的分数和\n",
    "        for key in user1event:\n",
    "            if key in user2event:\n",
    "                n += 1 \n",
    "                x = self.userEventScores[uid1,key]\n",
    "                y = self.userEventScores[uid2,key]\n",
    "                sum_x += x  \n",
    "                sum_y += y  \n",
    "        #print(\"n = %d sum_x = %d sum_y =%d\" %(n,sum_x,sum_y))\n",
    "        #如果两个用户都打过分的item不为空则计算两用户的相似度\n",
    "        if n > 0:  \n",
    "            #4.计算两个用户分别的平均分\n",
    "            avgx = sum_x/n\n",
    "            avgy = sum_y/n\n",
    "            #5.根据Pearson相关系数公式进行计算\n",
    "            for key in user1event:\n",
    "                if key in user2event:\n",
    "                    x = self.userEventScores[uid1,key]\n",
    "                    y = self.userEventScores[uid2,key] \n",
    "                    #print(\"x = %f y =%f\" %(x,y))\n",
    "                    sum_ExEy += (x-avgx)*(y-avgy)\n",
    "                    sum_Dx += pow((x-avgx), 2)\n",
    "                    sum_Dy += pow((y-avgy), 2)\n",
    "            denominator = sqrt(sum_Dx)*sqrt(sum_Dy) \n",
    "            if denominator != 0:  \n",
    "                similarity = sum_ExEy/denominator\n",
    "            #返回相关用户2都打过分的item的平均分，用做下一步计算\n",
    "            return similarity,sum_y/n\n",
    "        else:\n",
    "            return similarity,0\n",
    "\n",
    "    def userCFReco(self, userId, eventId):\n",
    "        \"\"\"\n",
    "        根据User-based协同过滤，得到event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i\n",
    "          for every other user v that has a preference for i\n",
    "            compute similarity s between u and v\n",
    "            incorporate v's preference for i weighted by s into running aversge\n",
    "        return top items ranked by weighted average\n",
    "        \"\"\"\n",
    "        #请补充完整代码\n",
    "        ans = 0.0\n",
    "        distances = []\n",
    "        #1.对于eventID,查看其它所有user是否对此event有打分\n",
    "        userIndex = self.userIndex[userId]\n",
    "        eventIndex = self.eventIndex[eventId]\n",
    "        eventUser = self.usersForItem[eventIndex]\n",
    "        userEvent = self.itemsForUser[userIndex]\n",
    "        #如果该用户没有参数任何活动，预测值为0\n",
    "        if len(userEvent) == 0:\n",
    "            return ans\n",
    "        #2.对于所有有打分的user，计算与此userID的相似度\n",
    "        for uid in eventUser:\n",
    "            if uid != userIndex:\n",
    "                distance,avgScore= self.sim_cal_UserCF(userIndex,uid)\n",
    "                distances.append((uid, distance, avgScore))\n",
    "        #3.返回以权重平均分排名的列表\n",
    "        distances.sort(key=lambda x: x[1],reverse=True)\n",
    "        #4.再取前20个用公式计算预测打分\n",
    "        sumScore = 0.0\n",
    "        totalDistance = 0.0 \n",
    "        sumRC = 0.0\n",
    "        for eid in userEvent:\n",
    "            sumScore += self.userEventScores[userIndex,eid]\n",
    "        avgScore = sumScore/len(userEvent)\n",
    "        for i in range(20):  \n",
    "            if i >= len(distances):\n",
    "                break\n",
    "            totalDistance += distances[i][1]\n",
    "            tmpUserEvent = self.itemsForUser[distances[i][0]]\n",
    "            if len(tmpUserEvent) == 0:\n",
    "                break\n",
    "            #tmpSumScore = 0.0\n",
    "            #for tmpeid in tmpUserEvent:\n",
    "            #    tmpSumScore += self.userEventScores[distances[i][0],tmpeid]\n",
    "            #读取sim_cal_UserCF计算得到的uid平均打分做下一步计算\n",
    "            tmpAvgScore = distances[i][2]\n",
    "            sumRC += distances[i][1]*(self.userEventScores[distances[i][0],eventIndex]-tmpAvgScore)\n",
    "            #print(\"tmpAvgScore=%f,Scores=%f\" %(tmpAvgScore,self.userEventScores[distances[i][0],eventIndex]))\n",
    "        if totalDistance==0.0:  \n",
    "            totalDistance=1.0 \n",
    "        ans = avgScore + sumRC/totalDistance\n",
    "        #print(\"ans=%f,avgScore=%f,sumRC=%f\" %(ans,avgScore,sumRC))\n",
    "        return ans\n",
    "\n",
    "\n",
    "    def sim_cal_ItemCF(self, i_id1, i_id2):\n",
    "        #计算Item i_id1和i_id2之间的相似性\n",
    "        #请补充完整代码\n",
    "        similarity = 0.0\n",
    "        #1.找到给两个item都打过分的所有userid，并获取打分\n",
    "        event1user = self.usersForItem[i_id1]\n",
    "        event2user = self.usersForItem[i_id2]\n",
    "        #2.根据Pearson相关系数公式进行计算，计算方法同sim_cal_UserCF\n",
    "        sum_x = 0  \n",
    "        sum_y = 0\n",
    "        n = 0  \n",
    "        sum_ExEy = 0\n",
    "        sum_Dx = 0\n",
    "        sum_Dy =0\n",
    "\n",
    "        for key in event1user:\n",
    "            if key in event2user:\n",
    "                n += 1 \n",
    "                x = self.userEventScores[key,i_id1]\n",
    "                y = self.userEventScores[key,i_id2]\n",
    "                sum_x += x  \n",
    "                sum_y += y  \n",
    "        if n != 0:  \n",
    "            avgx = sum_x/n\n",
    "            avgy = sum_y/n\n",
    "            for key in event1user:\n",
    "                if key in event2user:\n",
    "                    x = self.userEventScores[key,i_id1]\n",
    "                    y = self.userEventScores[key,i_id2]\n",
    "                    sum_ExEy += (x-avgx)*(y-avgy)\n",
    "                    sum_Dx += pow((x-avgx), 2)\n",
    "                    sum_Dy += pow((y-avgy), 2)\n",
    "            denominator = sqrt(sum_Dx)*sqrt(sum_Dy) \n",
    "            if denominator != 0:  \n",
    "                similarity = sum_ExEy/denominator\n",
    "        #print(\"item CF similarity = %f\" %(similarity))\n",
    "        return similarity     \n",
    "\n",
    "        #return num/den  \n",
    "            \n",
    "    def eventCFReco(self, userId, eventId):    \n",
    "        \"\"\"\n",
    "        根据基于物品的协同过滤，得到Event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i \n",
    "            for every item j that u has a preference for\n",
    "                compute similarity s between i and j\n",
    "                add u's preference for j weighted by s to a running average\n",
    "        return top items, ranked by weighted average\n",
    "        \"\"\"\n",
    "        #请补充完整代码\n",
    "        ans = 0.0\n",
    "        distances = []\n",
    "        userIndex = self.userIndex[userId]\n",
    "        eventIndex = self.eventIndex[eventId]\n",
    "        userEvent = self.itemsForUser[userIndex]\n",
    "        eventUser = self.usersForItem[eventIndex]\n",
    "        #1.查看event是否有user参加，如没有则反回相似度为0\n",
    "        if len(eventUser) == 0:\n",
    "            return ans\n",
    "        #2.对于userID对应的所有打分的event，计算与此eventID的相似度\n",
    "        for eventId in userEvent:\n",
    "            if eventId != eventIndex:\n",
    "                distance = self.sim_cal_ItemCF(eventIndex,eventId)\n",
    "                distances.append((eventId, distance))\n",
    "        #4.返回以权重平均分排名的列表\n",
    "        distances.sort(key=lambda x: x[1],reverse=True)\n",
    "        sumSim = 0.0\n",
    "        sumScr = 0.0\n",
    "        #5.再取前20个用公式计算预测打分\n",
    "        for i in range(20): \n",
    "            if i >= len(distances):\n",
    "                break\n",
    "            sumSim += distances[i][1]\n",
    "            sumScr += distances[i][1]*(self.userEventScores[userIndex,distances[i][0]])\n",
    "        if sumSim !=0:\n",
    "            ans = sumScr/sumSim\n",
    "        #print(\"===ans==%f=\" %(ans))\n",
    "        return ans\n",
    "    \n",
    "    def svdCFReco(self, userId, eventId):\n",
    "        #基于模型的协同过滤, SVD++/LFM\n",
    "        u = self.userIndex[userId]\n",
    "        i = self.eventIndex[eventId]\n",
    "\n",
    "        return self.pred_SVD(u,i)\n",
    "\n",
    "    def userReco(self, userId, eventId):\n",
    "        \"\"\"\n",
    "        类似基于User-based协同过滤，只是用户之间的相似度由用户本身的属性得到，计算event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i\n",
    "          for every other user v that has a preference for i\n",
    "            compute similarity s between u and v\n",
    "            incorporate v's preference for i weighted by s into running aversge\n",
    "        return top items ranked by weighted average\n",
    "        \"\"\"\n",
    "        i = self.userIndex[userId]\n",
    "        j = self.eventIndex[eventId]\n",
    "\n",
    "        vs = self.userEventScores[:, j]\n",
    "        sims = self.userSimMatrix[i, :]\n",
    "\n",
    "        prod = sims * vs\n",
    "\n",
    "        try:\n",
    "            return prod[0, 0] - self.userEventScores[i, j]\n",
    "        except IndexError:\n",
    "            return 0\n",
    "\n",
    "    def eventReco(self, userId, eventId):\n",
    "        \"\"\"\n",
    "        类似基于Item-based协同过滤，只是item之间的相似度由item本身的属性得到，计算Event的推荐度\n",
    "        基本的伪代码思路如下：\n",
    "        for item i \n",
    "          for every item j that u has a preference for\n",
    "            compute similarity s between i and j\n",
    "            add u's preference for j weighted by s to a running average\n",
    "        return top items, ranked by weighted average\n",
    "        \"\"\"\n",
    "        i = self.userIndex[userId]\n",
    "        j = self.eventIndex[eventId]\n",
    "        js = self.userEventScores[i, :]\n",
    "        psim = self.eventPropSim[:, j]\n",
    "        csim = self.eventContSim[:, j]\n",
    "        pprod = js * psim\n",
    "        cprod = js * csim\n",
    "\n",
    "        pscore = 0\n",
    "        cscore = 0\n",
    "        try:\n",
    "            pscore = pprod[0, 0] - self.userEventScores[i, j]\n",
    "        except IndexError:\n",
    "            pass\n",
    "        try:\n",
    "            cscore = cprod[0, 0] - self.userEventScores[i, j]\n",
    "        except IndexError:\n",
    "            pass\n",
    "        return pscore, cscore\n",
    "\n",
    "    def userPop(self, userId):\n",
    "        \"\"\"\n",
    "        基于用户的朋友个数来推断用户的社交程度\n",
    "        主要的考量是如果用户的朋友非常多，可能会更倾向于参加各种社交活动\n",
    "        \"\"\"\n",
    "        #if self.userIndex.has_key(userId):\n",
    "        if userId in self.userIndex:\n",
    "            i = self.userIndex[userId]\n",
    "            try:\n",
    "                return self.numFriends[0, i]\n",
    "            except IndexError:\n",
    "                return 0\n",
    "        else:\n",
    "            return 0\n",
    "\n",
    "    def friendInfluence(self, userId):\n",
    "        \"\"\"\n",
    "        朋友对用户的影响\n",
    "        主要考虑用户所有的朋友中，有多少是非常喜欢参加各种社交活动/event的\n",
    "        用户的朋友圈如果都积极参与各种event，可能会对当前用户有一定的影响\n",
    "        \"\"\"\n",
    "        nusers = np.shape(self.userFriends)[1]\n",
    "        #print(\"nusers=%d\" %(nusers))\n",
    "        i = self.userIndex[userId]\n",
    "        return (self.userFriends[i, :].sum(axis=0) / nusers)[0,0]\n",
    "\n",
    "    def eventPop(self, eventId):\n",
    "        \"\"\"\n",
    "        本活动本身的热度\n",
    "        主要是通过参与的人数来界定的\n",
    "        \"\"\"\n",
    "        i = self.eventIndex[eventId]\n",
    "        return self.eventPopularity[i, 0]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generateRSData(RS, train=True, header=True):\n",
    "    \"\"\"\n",
    "    把前面user-based协同过滤 和 item-based协同过滤，以及各种热度和影响度作为特征组合在一起\n",
    "    生成新的训练数据，用于分类器分类使用\n",
    "    \"\"\"\n",
    "    fn = \"train.csv\" if train else \"test.csv\"\n",
    "    fin = open(fn, 'rb')\n",
    "    fout = open(\"RS_\" + fn, 'wb')\n",
    "    \n",
    "    #忽略第一行（列名字）\n",
    "    fin.readline().decode().strip().split(\",\")\n",
    "    \n",
    "    # write output header\n",
    "    if header:\n",
    "        ocolnames = [\"invited\", \"userCF_reco\", \"evtCF_reco\",\"svdCF_reco\",\"user_reco\", \"evt_p_reco\",\n",
    "        \"evt_c_reco\", \"user_pop\", \"frnd_infl\", \"evt_pop\"]\n",
    "        if train:\n",
    "            ocolnames.append(\"interested\")\n",
    "            ocolnames.append(\"not_interested\")\n",
    "        fout.write((\",\".join(ocolnames) + \"\\n\").encode())\n",
    "    \n",
    "    ln = 0\n",
    "    for line in fin:\n",
    "        ln += 1\n",
    "        if ln%500 == 0:\n",
    "            print(\"%s:%d (userId, eventId)=(%s, %s)\" % (fn, ln, userId, eventId))\n",
    "            #break;\n",
    "      \n",
    "        cols = line.decode().strip().split(\",\")\n",
    "        userId = cols[0]\n",
    "        eventId = cols[1]\n",
    "        invited = cols[2]\n",
    "        userCF_reco = RS.userCFReco(userId, eventId)\n",
    "        itemCF_reco = RS.eventCFReco(userId, eventId)\n",
    "        svdCF_reco = RS.svdCFReco(userId, eventId)\n",
    "        \n",
    "        user_reco = RS.userReco(userId, eventId)\n",
    "        evt_p_reco, evt_c_reco = RS.eventReco(userId, eventId)\n",
    "        user_pop = RS.userPop(userId)\n",
    "        frnd_infl = RS.friendInfluence(userId)\n",
    "        evt_pop = RS.eventPop(eventId)\n",
    "        ocols = [invited, userCF_reco, itemCF_reco, svdCF_reco,user_reco, evt_p_reco,\n",
    "        evt_c_reco, user_pop, frnd_infl, evt_pop]\n",
    "   \n",
    "        if train:\n",
    "            ocols.append(cols[4]) # interested\n",
    "            ocols.append(cols[5]) # not_interested\n",
    "        fout.write((\",\".join(map(lambda x: str(x), ocols)) + \"\\n\").encode())\n",
    "    \n",
    "    fin.close()\n",
    "    fout.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SVD Train...\n",
      "0.2682815950123393\n",
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n",
      "11\n",
      "12\n",
      "13\n",
      "14\n",
      "15\n",
      "16\n",
      "17\n",
      "18\n",
      "19\n",
      "20\n",
      "21\n",
      "22\n",
      "23\n",
      "24\n",
      "25\n",
      "26\n",
      "27\n",
      "28\n",
      "29\n",
      "30\n",
      "31\n",
      "32\n",
      "33\n",
      "34\n",
      "35\n",
      "36\n",
      "37\n",
      "38\n",
      "39\n",
      "40\n",
      "41\n",
      "42\n",
      "43\n",
      "44\n",
      "45\n",
      "46\n",
      "47\n",
      "48\n",
      "49\n",
      "50\n",
      "51\n",
      "52\n",
      "53\n",
      "54\n",
      "55\n",
      "56\n",
      "57\n",
      "58\n",
      "59\n",
      "60\n",
      "61\n",
      "62\n",
      "63\n",
      "64\n",
      "65\n",
      "66\n",
      "67\n",
      "68\n",
      "69\n",
      "70\n",
      "71\n",
      "72\n",
      "73\n",
      "74\n",
      "75\n",
      "76\n",
      "77\n",
      "78\n",
      "79\n",
      "80\n",
      "81\n",
      "82\n",
      "83\n",
      "84\n",
      "85\n",
      "86\n",
      "87\n",
      "88\n",
      "89\n",
      "90\n",
      "91\n",
      "92\n",
      "93\n",
      "94\n",
      "95\n",
      "96\n",
      "97\n",
      "98\n",
      "99\n",
      "SVD trained\n",
      "生成训练数据...\n",
      "\n",
      "train.csv:500 (userId, eventId)=(123290209, 1887085024)\n",
      "train.csv:1000 (userId, eventId)=(272886293, 199858305)\n",
      "train.csv:1500 (userId, eventId)=(395305791, 1582270949)\n",
      "train.csv:2000 (userId, eventId)=(527523423, 3272728211)\n",
      "train.csv:2500 (userId, eventId)=(651258472, 792632006)\n",
      "train.csv:3000 (userId, eventId)=(811791433, 524756826)\n",
      "train.csv:3500 (userId, eventId)=(985547042, 1269035551)\n",
      "train.csv:4000 (userId, eventId)=(1107615001, 173949238)\n",
      "train.csv:4500 (userId, eventId)=(1236336671, 3849306291)\n",
      "train.csv:5000 (userId, eventId)=(1414301782, 2652356640)\n",
      "train.csv:5500 (userId, eventId)=(1595465532, 955398943)\n",
      "train.csv:6000 (userId, eventId)=(1747091728, 2131379889)\n",
      "train.csv:6500 (userId, eventId)=(1914182220, 955398943)\n",
      "train.csv:7000 (userId, eventId)=(2071842684, 1076364848)\n",
      "train.csv:7500 (userId, eventId)=(2217853337, 3051438735)\n",
      "train.csv:8000 (userId, eventId)=(2338481531, 2525447278)\n",
      "train.csv:8500 (userId, eventId)=(2489551967, 520657921)\n",
      "train.csv:9000 (userId, eventId)=(2650493630, 87962584)\n",
      "train.csv:9500 (userId, eventId)=(2791418962, 4223848259)\n",
      "train.csv:10000 (userId, eventId)=(2903662804, 2791462807)\n",
      "train.csv:10500 (userId, eventId)=(3036141956, 3929507420)\n",
      "train.csv:11000 (userId, eventId)=(3176074542, 3459485614)\n",
      "train.csv:11500 (userId, eventId)=(3285425249, 2271782630)\n",
      "train.csv:12000 (userId, eventId)=(3410667855, 1063772489)\n",
      "train.csv:12500 (userId, eventId)=(3531604778, 2584839423)\n",
      "train.csv:13000 (userId, eventId)=(3686871863, 53495098)\n",
      "train.csv:13500 (userId, eventId)=(3833637800, 2415873572)\n",
      "train.csv:14000 (userId, eventId)=(3944021305, 2096772901)\n",
      "train.csv:14500 (userId, eventId)=(4075466480, 3567240505)\n",
      "train.csv:15000 (userId, eventId)=(4197193550, 1628057176)\n",
      "生成预测数据...\n",
      "\n",
      "test.csv:500 (userId, eventId)=(182290053, 2529072432)\n",
      "test.csv:1000 (userId, eventId)=(433510318, 4244463632)\n",
      "test.csv:1500 (userId, eventId)=(632808865, 2845303452)\n",
      "test.csv:2000 (userId, eventId)=(813611885, 2036538169)\n",
      "test.csv:2500 (userId, eventId)=(1010701404, 303459881)\n",
      "test.csv:3000 (userId, eventId)=(1210932037, 2529072432)\n",
      "test.csv:3500 (userId, eventId)=(1452921099, 2705317682)\n",
      "test.csv:4000 (userId, eventId)=(1623287180, 1626678328)\n",
      "test.csv:4500 (userId, eventId)=(1855201342, 2603032829)\n",
      "test.csv:5000 (userId, eventId)=(2083900381, 2529072432)\n",
      "test.csv:5500 (userId, eventId)=(2318415276, 2509151803)\n",
      "test.csv:6000 (userId, eventId)=(2528161539, 4025975316)\n",
      "test.csv:6500 (userId, eventId)=(2749110768, 4244406355)\n",
      "test.csv:7000 (userId, eventId)=(2927772127, 1532377761)\n",
      "test.csv:7500 (userId, eventId)=(3199685636, 1776393554)\n",
      "test.csv:8000 (userId, eventId)=(3393388475, 680270887)\n",
      "test.csv:8500 (userId, eventId)=(3601169721, 154434302)\n",
      "test.csv:9000 (userId, eventId)=(3828963415, 3067222491)\n",
      "test.csv:9500 (userId, eventId)=(4018723397, 2522610844)\n",
      "test.csv:10000 (userId, eventId)=(4180064266, 2658555390)\n"
     ]
    }
   ],
   "source": [
    "RS = RecommonderSystem()\n",
    "print(\"生成训练数据...\\n\")\n",
    "generateRSData(RS,train=True,  header=True)\n",
    "\n",
    "print(\"生成预测数据...\\n\")\n",
    "generateRSData(RS, train=False, header=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这次的作业比较难，不像以前只需要读用标准接口进行计算就可以，需要自己实现算法，但更难的是理解算法的实现原理和过程\n",
    "在做作业过程中遇到以下几个疑点，请老师帮忙解答下：\n",
    "1.作业要求“实现基于用户的协同过滤（用户本身，用户好友分析）”但思考很久也没想出用户好友分析怎么用在协同过滤中，所以没有完成此项。\n",
    "  实现基于物品的协同过滤中用户活动关联分析也一样没有完成\n",
    "2.相关系数的计算一般都是用Pearson相关系数吗？Pearson相关系数的三种公式计算出的结果是一一致的吗？\n",
    "3.在userCFReco中预测算法要用到两个用户的平均分，这个平均分是两个用户分别对其所有物品打分的平均分还是两个用户共同打过分的物品的平均分？\n",
    "4.用户/物品邻居数量的选择如何定？计算物品预测值时发现邻居数分别设为3和20，得到的预测值相差非常大，设为3时预测值在-2：2,而设为20时预测值会达到-20：20甚至更大，为何会这样？\n",
    "5.userCFReco，eventCFReco计算得到的值ans是否应该限定在0-1范围内？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "时间、地点等特征都没有处理了，可以考虑用户看到event的时间与event开始时间的差、用户地点和event地点的差异。。。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
